package net.htjs.juc.chapter06.accountcas;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 使用CAS实现线程安全
 * volatile
 * 获取共享变量时，为了保证该变量的可见性，需要使用volatile修饰
 * 它可以用来修饰成员变量和静态变量，它可以避免线程从自己的工作缓存中查找变量的值，
 * 必须从主存中获取它的值，现成操作volatile变量都是直接操作主存，即一个线程对volatile变量
 * 的修改，对另一个线程可见
 * 注意:
 * volatile仅保证了共享变量的可见性，让其他线程能够看到最新值，但是不能解决指令交错的问题(不能保证原子性)
 *
 * CAS必须借助volatile才能读取到共享变量的最新值来实现(比较并交换)的效果
 *
 * CAS的特点
 * 结合CAS和volatile可以实现无锁并发，适用于线程数少，多核CPU的场景下
 * CAS是基于乐观锁的思想，最乐观的估计，不怕别的线程来修改共享变量，就算改了也没关系，我吃亏点再重试呗
 * synchronized是基于悲观锁的思想，最悲观的估计，得防着其他线程来修改共享变量，我上了锁你们都别想改，我改完了解开锁，你们才有机会
 * CAS体现的是无锁并发，无阻塞并发
 * 因为没使用synchroinzed,所以线程不会陷入阻塞，这是效率提升的因素之一
 * 但如果锁竞争激烈，可以想到重试必然频繁发生，反而效率会受影响
 */
public class AccountCas implements Account {

    private AtomicInteger balance;

    public AccountCas(Integer balance) {
        this.balance = new AtomicInteger(balance);
    }

    @Override
    public Integer getBalance() {
        return this.balance.get();
    }

    @Override
    public void withdraw(Integer amount) {
        /*while(true) {
            //获取余额的最新值
            int prev = balance.get();
            //要修改都饿余额
            int next = prev - amount;
            //真正修改
            if(balance.compareAndSet(prev, next)) {
                break;
            }
        }*/
        balance.getAndAdd(-amount);
    }

    public static void main(String[] args) {
        AccountCas account = new AccountCas(10000);
        Account.demo( account);
    }
}
